<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../Universal.css">
</head>
<body>
    
    <div id="cnblogs_post_body" class="blogpost-body">
        <h2>java中流的体系结构</h2>
    <p>IO流主要是用来处理设备之间的数据传输。<br><br>流按操作的数据可分为字符流和字节流。字节流用于处理二进制文件，比如音频、视频等；字符流用于处理带有中文字符的文件，比如文本文件。</p>
    <p>流按照数据的流向可分为输入流和输出流。输入输出是相对于内存来说的，输入就是把某个地方（比如磁盘）的数据读到内存中，输出就是把数据从内存中写到某个地方（比如磁盘）。<br>java中流的体系结构如下，由于实现类实在太多，标记颜色的为常用的类。</p>
    <p>&nbsp;<img src="https://images2018.cnblogs.com/blog/612774/201807/612774-20180731103830968-1394456905.png" alt=""></p>
    <h2>字节流</h2>
    <h3><code>FileOutputStream</code>&nbsp;</h3>
    <p><code>我们常用来向文件中写入数据的流是FileOutputStream</code>&nbsp;，主要用于写入诸如图像数据之类的原始字节的流。</p>
    <p>构造函数如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
    FileOutputStream(File file, </span><span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> append)  创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
    FileOutputStream(FileDescriptor fdObj)  创建一个向指定文件描述符处写入数据的输出文件流，该文件描述符表示一个到文件系统中的某个实际文件的现有连接。
    FileOutputStream(String name)  创建一个向具有指定名称的文件中写入数据的输出文件流。
    FileOutputStream(String name, </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> append)  创建一个向具有指定 name 的文件中写入数据的输出文件流。</pre>
    </div>
    <p>写入的方法有3个，具体如下：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">byte</span>[] b)  将 b.length 个字节从指定 <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)"> 数组写入此文件输出流中。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">byte</span>[] b, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span> len)  将指定 <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)"> 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">int</span> b) 将指定字节写入此文件输出流。</pre>
    </div>
    <p>举个例子：</p>
    <div class="cnblogs_code">
    <pre> String filePath =  "D:\\Learning\\doc\\test.txt"<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 向test.txt文件中写入数据</span>
     FileOutputStream fos=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(filePath);
     fos.write(</span>"学习IO流"<span style="color: rgba(0, 0, 0, 1)">.getBytes());
     fos.close();</span></pre>
    </div>
    <h3><code>FileInputStream</code>&nbsp;</h3>
    <p>和FileOutputStream对应的是<code>FileInputStream</code>&nbsp;，用于读取诸如图像数据之类的原始字节流，文件不存在会创建。</p>
    <p>构造函数如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">FileInputStream(File file)  通过打开一个到实际文件的连接来创建一个 FileInputStream，该文件通过文件系统中的 File 对象 file 指定。
    FileInputStream(FileDescriptor fdObj)  通过使用文件描述符 fdObj 创建一个 FileInputStream，该文件描述符表示到文件系统中某个实际文件的现有连接。
    FileInputStream(String name)  通过打开一个到实际文件的连接来创建一个 FileInputStream，该文件通过文件系统中的路径名 name 指定。</span></pre>
    </div>
    <p>读取的方法如下，read方法从此输入流中读取数据字节。如果没有输入可用，则此方法将阻塞。如果因为已经到达文件末尾而没有更多的数据，则返回&nbsp;<code>-1</code>。</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">    read()  从此输入流中读取一个数据字节。
     </span><span style="color: rgba(0, 0, 255, 1)">int</span>    read(<span style="color: rgba(0, 0, 255, 1)">byte</span>[] b)  从此输入流中将最多 b.length 个字节的数据读入一个 <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)"> 数组中。
     </span><span style="color: rgba(0, 0, 255, 1)">int</span>    read(<span style="color: rgba(0, 0, 255, 1)">byte</span>[] b, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span> len)  从此输入流中将最多 len 个字节的数据读入一个 <span style="color: rgba(0, 0, 255, 1)">byte</span> 数组中。</pre>
    </div>
    <p>举个例子：</p>
    <div class="cnblogs_code">
    <pre>String filePath =  "D:\\Learning\\doc\\test1.txt"<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">读取test文件内容</span>
    FileInputStream fis=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(filePath);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式一：一个字节一个字节的读取</span>
    <span style="color: rgba(0, 0, 255, 1)">int</span> ch=0<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((ch=fis.read())!=-1<span style="color: rgba(0, 0, 0, 1)">) {
       System.out.print((</span><span style="color: rgba(0, 0, 255, 1)">char</span><span style="color: rgba(0, 0, 0, 1)">)ch);
    }
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式二：批量读取到缓冲区，推荐使用方式</span>
    <span style="color: rgba(0, 0, 255, 1)">int</span> len=0<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] buffer=<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[1024<span style="color: rgba(0, 0, 0, 1)">];
    </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len=fis.read(buffer))!=-1<span style="color: rgba(0, 0, 0, 1)">){
        System.out.print(</span><span style="color: rgba(0, 0, 255, 1)">new</span> String(buffer,0<span style="color: rgba(0, 0, 0, 1)">,len));
    }
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式三：一次性读取，不建议使用，如果文件过大，那么数组会非常大，可能内存不够，创建数组也会非常耗时
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">fis.available()获取文件的字节数</span>
    <span style="color: rgba(0, 0, 255, 1)">byte</span>[] buf = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[fis.available()];
    fis.read(buf);
    System.out.println(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> String(buf));
    fis.close();</span></pre>
    </div>
    <p>下面代码演示了如何拷贝文件：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需求：把vedio拷贝到vedio1</span>
    String sourceFilePath = "D:\\Learning\\doc\\vedio.avi"<span style="color: rgba(0, 0, 0, 1)">;
    String destFilePath </span>= "D:\\Learning\\doc\\vedio1.avi"<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建读取文件对象</span>
    FileInputStream fis=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(sourceFilePath);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建写入文件对象</span>
    FileOutputStream fos=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(destFilePath);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建1M的缓冲区</span>
    <span style="color: rgba(0, 0, 255, 1)">byte</span>[] buffer =<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[1024*1024*1<span style="color: rgba(0, 0, 0, 1)">];
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">每次读取的长度,可能最后一次的读取长度并没有buffer.length那么多</span>
    <span style="color: rgba(0, 0, 255, 1)">int</span> len=0<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len=fis.read(buffer))!=-1<span style="color: rgba(0, 0, 0, 1)">){
        fos.write(buffer,</span>0<span style="color: rgba(0, 0, 0, 1)">,len);
    }
    fos.close();
    fis.close();</span></pre>
    </div>
    <p>当然，如果是很小的文件，也可以直接向下面这样，但对于大文件，禁止使用：</p>
    <div class="cnblogs_code">
    <pre>        <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需求：把vedio拷贝到vedio1</span>
            String sourceFilePath = "D:\\Learning\\doc\\vedio.avi"<span style="color: rgba(0, 0, 0, 1)">;
            String destFilePath </span>= "D:\\Learning\\doc\\vedio1.avi"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建读取文件对象</span>
            FileInputStream fis=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(sourceFilePath);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建写入文件对象</span>
            FileOutputStream fos=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(destFilePath);
            </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] buf = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[fis.available()];
            fis.read(buf);
            fos.write(buf);
    
            fos.close();
            fis.close();</span></pre>
    </div>
    <p>上面我们手动创建了缓冲区用来提高字节读写效率，java也提供了同样的功能，即BufferInputStream，BufferOutputStream。</p>
    <h3>BufferedInputStream</h3>
    <p>BufferedInputStream 为另一个输入流添加一些功能，即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时，会创建一个内部缓冲区数组。</p>
    <p>构造函数如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">BufferedInputStream(InputStream in) 创建一个 BufferedInputStream 并保存其参数，即输入流 in，以便将来使用。
    BufferedInputStream(InputStream in, </span><span style="color: rgba(0, 0, 255, 1)">int</span> size) 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数，即输入流 in，以便将来使用。</pre>
    </div>
    <p>读取方法如下：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">    read()  参见 InputStream 的 read 方法的常规协定。
     </span><span style="color: rgba(0, 0, 255, 1)">int</span>    read(<span style="color: rgba(0, 0, 255, 1)">byte</span>[] b, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span> len)  从此字节输入流中给定偏移量处开始将各字节读取到指定的 <span style="color: rgba(0, 0, 255, 1)">byte</span> 数组中。</pre>
    </div>
    <h3>BufferOutputStream</h3>
    <p>该类实现缓冲的输出流。通过设置这种输出流，应用程序就可以将各个字节写入底层输出流中，而不必针对每次字节写入调用底层系统。</p>
    <p>构造方法如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">BufferedOutputStream(OutputStream out)  创建一个新的缓冲输出流，以将数据写入指定的底层输出流。
    BufferedOutputStream(OutputStream out, </span><span style="color: rgba(0, 0, 255, 1)">int</span> size)  创建一个新的缓冲输出流，以将具有指定缓冲区大小的数据写入指定的底层输出流。</pre>
    </div>
    <p>write方法如下：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">byte</span>[] b, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span> len)  将指定 <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)"> 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">int</span> b)  将指定的字节写入此缓冲的输出流。</pre>
    </div>
    <p>下面来看看如何使用：</p>
    <div class="cnblogs_code">
    <pre>        <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需求：把vedio拷贝到vedio1</span>
            String sourceFilePath = "D:\\Learning\\doc\\vedio.avi"<span style="color: rgba(0, 0, 0, 1)">;
            String destFilePath </span>= "D:\\Learning\\doc\\vedio1.avi"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建读取文件对象</span>
            FileInputStream fis=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(sourceFilePath);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建写入文件对象</span>
            FileOutputStream fos=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(destFilePath);
            BufferedInputStream bis</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedInputStream(fis);
            BufferedOutputStream bos</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedOutputStream(fos);
    
            </span><span style="color: rgba(0, 0, 255, 1)">int</span> len =0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len=bis.read())!=-1<span style="color: rgba(0, 0, 0, 1)">){
                bos.write(len);
            }
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">缓冲流是在普通流的基础上多了一个缓冲区  ,   
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 当读或写的数据达到一定量,再自动往文件里进行读写,如果没有装满缓冲区文件就已经读(写)完毕 ,   
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 那么这个时候已经读写到缓冲区的数据需要手动使其朝目标文件进行读写.
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">所以使用缓冲流一定要调用flush方法</span>
    <span style="color: rgba(0, 0, 0, 1)">        bos.flush();
            bis.close();
            bos.close();</span></pre>
    </div>
    <p>当然，也可以自己再创建一个缓冲区进一步提高效率，也可以在构造函数的第二个参数传入缓冲区大小：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">import</span> java.io.*<span style="color: rgba(0, 0, 0, 1)">;
    
    </span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Test {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[]args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">测试拷贝一个大小为200M时的性能问题</span>
    <span style="color: rgba(0, 0, 0, 1)">        test1();
            test2();
            test3();
        }
    
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">int</span> BUFFER_SIZE = 1024 * 1024 * 1<span style="color: rgba(0, 0, 0, 1)">;
    
        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 方式一：不加缓冲区的情况
         *
         * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> IOException
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> test1() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需求：把vedio拷贝到vedio1</span>
            String sourceFilePath = "E:\\desktop.zip"<span style="color: rgba(0, 0, 0, 1)">;
            String destFilePath </span>= "E:\\desktop1.zip"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建读取文件对象</span>
            FileInputStream fis = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(sourceFilePath);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建写入文件对象</span>
            FileOutputStream fos = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(destFilePath);
            BufferedInputStream bis </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedInputStream(fis);
            BufferedOutputStream bos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedOutputStream(fos);
    
            </span><span style="color: rgba(0, 0, 255, 1)">long</span> start =<span style="color: rgba(0, 0, 0, 1)"> System.currentTimeMillis();
            </span><span style="color: rgba(0, 0, 255, 1)">int</span> len = 0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len = bis.read()) != -1<span style="color: rgba(0, 0, 0, 1)">) {
                bos.write(len);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">long</span> end =<span style="color: rgba(0, 0, 0, 1)"> System.currentTimeMillis();
            System.out.println(end </span>- start);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">21365</span>
    <span style="color: rgba(0, 0, 0, 1)">
            bos.flush();
            bis.close();
            bos.close();
        }
    
        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 方式二：加缓冲区的情况
         * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> IOException
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> test2() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需求：把vedio拷贝到vedio1</span>
            String sourceFilePath = "E:\\desktop.zip"<span style="color: rgba(0, 0, 0, 1)">;
            String destFilePath </span>= "E:\\desktop2.zip"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建读取文件对象</span>
            FileInputStream fis = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(sourceFilePath);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建写入文件对象</span>
            FileOutputStream fos = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(destFilePath);
            BufferedInputStream bis </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedInputStream(fis);
            BufferedOutputStream bos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedOutputStream(fos);
    
            </span><span style="color: rgba(0, 0, 255, 1)">long</span> start =<span style="color: rgba(0, 0, 0, 1)"> System.currentTimeMillis();
            </span><span style="color: rgba(0, 0, 255, 1)">byte</span>[] buffer = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span><span style="color: rgba(0, 0, 0, 1)">[BUFFER_SIZE];
            </span><span style="color: rgba(0, 0, 255, 1)">int</span> len = 0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len = bis.read(buffer)) != -1<span style="color: rgba(0, 0, 0, 1)">) {
                bos.write(buffer, </span>0<span style="color: rgba(0, 0, 0, 1)">, len);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">long</span> end =<span style="color: rgba(0, 0, 0, 1)"> System.currentTimeMillis();
            System.out.println(end </span>- start);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">975</span>
    <span style="color: rgba(0, 0, 0, 1)">        bos.flush();
            bis.close();
            bos.close();
        }
    
        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 方式3：构造函数加入缓冲大小的情况
         * </span><span style="color: rgba(128, 128, 128, 1)">@throws</span><span style="color: rgba(0, 128, 0, 1)"> IOException
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> test3() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> IOException {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 需求：把vedio拷贝到vedio1</span>
            String sourceFilePath = "E:\\desktop.zip"<span style="color: rgba(0, 0, 0, 1)">;
            String destFilePath </span>= "E:\\desktop3.zip"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建读取文件对象</span>
            FileInputStream fis = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(sourceFilePath);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建写入文件对象</span>
            FileOutputStream fos = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(destFilePath);
            BufferedInputStream bis </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedInputStream(fis, BUFFER_SIZE);
            BufferedOutputStream bos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedOutputStream(fos, BUFFER_SIZE);
    
            </span><span style="color: rgba(0, 0, 255, 1)">long</span> start =<span style="color: rgba(0, 0, 0, 1)"> System.currentTimeMillis();
            </span><span style="color: rgba(0, 0, 255, 1)">int</span> len = 0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len = bis.read()) != -1<span style="color: rgba(0, 0, 0, 1)">) {
                bos.write(len);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">long</span> end =<span style="color: rgba(0, 0, 0, 1)"> System.currentTimeMillis();
            System.out.println(end </span>- start);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">3036</span>
    <span style="color: rgba(0, 0, 0, 1)">        bos.flush();
            bis.close();
            bos.close();
        }
    }</span></pre>
    </div>
    <p>由此可见，手动加缓冲区的效率最高。</p>
    <p>上面对于IO的异常处理是直接抛出，并未处理，下面介绍一下IO流的正确异常处理方式：</p>
    <div class="cnblogs_code">
    <pre>   String filePath = "D:\\Learning\\doc\\test.txt"<span style="color: rgba(0, 0, 0, 1)">;
            FileOutputStream fos</span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                fos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(filePath);
                fos.write(</span>"123456"<span style="color: rgba(0, 0, 0, 1)">.getBytes());
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (FileNotFoundException e) {
                e.printStackTrace();
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                e.printStackTrace();
            }</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {<br>　　　　　　　if(fos!=null){　 
                　　</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                    　　</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">一定要记得关闭流，否则文件可能一直被占用而无法操作</span>
    <span style="color: rgba(0, 0, 0, 1)">                　　fos.close();
                　　} </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                    　　e.printStackTrace();
                　　}<br>　　　　　　}
            }</span></pre>
    </div>
    <h2>字符流</h2>
    <p>上面介绍了字节流，如果我们写入的是中文，然后使用字节流读取出来，就会出现乱码。</p>
    <div class="cnblogs_code">
    <pre>        String filePath = "D:\\Learning\\doc\\test.txt"<span style="color: rgba(0, 0, 0, 1)">;
            FileOutputStream fos</span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            FileInputStream fis </span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                fos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(filePath);
                fis</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(filePath);
                fos.write(</span>"学习IO流"<span style="color: rgba(0, 0, 0, 1)">.getBytes());
    
                </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> ch;
                </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((ch=fis.read())!=-1<span style="color: rgba(0, 0, 0, 1)">){
                    System.out.print((</span><span style="color: rgba(0, 0, 255, 1)">char</span>)ch);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">å­¦ä¹&nbsp;IOæµ</span>
    <span style="color: rgba(0, 0, 0, 1)">            }
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (FileNotFoundException e) {
                e.printStackTrace();
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                e.printStackTrace();
            }</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {<br>　　　　　　　　　　//忘了判断null
                    fis.close();
                    fos.close();
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                    e.printStackTrace();
                }
            }
        }</span></pre>
    </div>
    <p>为什么会乱码呢?因为java中的char存的是Unicode字符，占用2个字节，而中文也是2个字节，上面的代码每次去一个字节区unicode字符集中查找，肯定找到的不是对应的中文，因此乱码。下面对上面的代码改造一下，手动指定编码方式，就可以解决乱码问题。关于字符的编码问题可以参考<a href="http://www.imkevinyang.com/2010/06/%E5%85%B3%E4%BA%8E%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%EF%BC%8C%E4%BD%A0%E6%89%80%E9%9C%80%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84.html" target="_blank">这里</a>。</p>
    <div class="cnblogs_code">
    <pre>        String filePath = "D:\\Learning\\doc\\test.txt"<span style="color: rgba(0, 0, 0, 1)">;
            FileOutputStream fos</span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            FileInputStream fis </span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                fos </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(filePath);
                fis</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileInputStream(filePath);
                fos.write(</span>"学习IO流".getBytes("UTF-8"<span style="color: rgba(0, 0, 0, 1)">));
                </span><span style="color: rgba(0, 0, 255, 1)">byte</span> [] buffer =<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">byte</span>[1024<span style="color: rgba(0, 0, 0, 1)">];
                </span><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> len;
                </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len=fis.read(buffer))!=-1<span style="color: rgba(0, 0, 0, 1)">){
                    System.out.print(</span><span style="color: rgba(0, 0, 255, 1)">new</span> String(buffer,0,len,"UTF-8"<span style="color: rgba(0, 0, 0, 1)">));
                }
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (FileNotFoundException e) {
                e.printStackTrace();
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                e.printStackTrace();
            }</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {<br>　　　　　　　　　　//忘了判断null
                    fis.close();
                    fos.close();
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                    e.printStackTrace();
                }
            }
        }</span></pre>
    </div>
    <p>上面的代码相对比较繁琐，java给我们提供了字符流，方便对中文等字符进行处理，下面来看看常用的FileReader和FileWriter。</p>
    <h3>FileWriter</h3>
    <p>FileWriter 用于写入字符流。用来写入字符文件的便捷类。使用平台（操作系统）默认字符编码。比如Windows简体中文版操作系统使用的编码为gbk。</p>
    <p>构造函数如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">FileWriter(File file)  根据给定的 File 对象构造一个 FileWriter 对象。
    FileWriter(File file, </span><span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> append)  根据给定的 File 对象构造一个 FileWriter 对象。
    FileWriter(FileDescriptor fd)  构造与某个文件描述符相关联的 FileWriter 对象。
    FileWriter(String fileName)  根据给定的文件名构造一个 FileWriter 对象。
    FileWriter(String fileName, </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> append)  根据给定的文件名以及指示是否附加写入数据的 <span style="color: rgba(0, 0, 255, 1)">boolean</span> 值来构造 FileWriter 对象。</pre>
    </div>
    <p>写入方法如下：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">char</span><span style="color: rgba(0, 0, 0, 1)">[] cbuf)  写入字符数组。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> c)   写入单个字符。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">    write(String str)  写入字符串。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">char</span>[] cbuf, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> len)  写入字符数组的某一部分。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(String str, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span> len)  写入字符串的某一部分。</pre>
    </div>
    <p>举个例子：</p>
    <div class="cnblogs_code">
    <pre>    String filePath = "D:\\Learning\\doc\\test.txt"<span style="color: rgba(0, 0, 0, 1)">;
            FileWriter fw</span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                fw </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileWriter(filePath);
                fw.write(</span>"学习IO流"<span style="color: rgba(0, 0, 0, 1)">);
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                e.printStackTrace();
            }</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">字符流如果不关闭，写入不会成功，因为字符流关闭之前会先刷新一下
                    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">也可以手动刷新<br>　　　　　　　　　 //忘了判断null</span>
    <span style="color: rgba(0, 0, 0, 1)">                fw.flush();
                    fw.close();
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                    e.printStackTrace();
                }
            }</span></pre>
    </div>
    <h3>FileReader</h3>
    <p><code>FileReader</code>&nbsp;用于读取字符流。用来读取字符文件的便捷类。</p>
    <p>构造方法如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">FileReader(File file)  在给定从中读取数据的 File 的情况下创建一个新 FileReader。
    FileReader(FileDescriptor fd)  在给定从中读取数据的 FileDescriptor 的情况下创建一个新 FileReader。
    FileReader(String fileName)   在给定从中读取数据的文件名的情况下创建一个新 FileReader。</span></pre>
    </div>
    <p>读取方法如下：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">    read()  读取单个字符。
     </span><span style="color: rgba(0, 0, 255, 1)">int</span>    read(<span style="color: rgba(0, 0, 255, 1)">char</span><span style="color: rgba(0, 0, 0, 1)">[] cbuf)  将字符读入数组。
     </span><span style="color: rgba(0, 0, 255, 1)">int</span>    read(<span style="color: rgba(0, 0, 255, 1)">char</span>[] cbuf, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> len)  将字符读入数组的某一部分。
     </span><span style="color: rgba(0, 0, 255, 1)">int</span>    read(CharBuffer target)  试图将字符读入指定的字符缓冲区。</pre>
    </div>
    <p>举个例子：</p>
    <div class="cnblogs_code">
    <pre> String filePath = "D:\\Learning\\doc\\test.txt"<span style="color: rgba(0, 0, 0, 1)">;
            FileReader fr </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                fr </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileReader(filePath);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式一：一次读取一个字符（2个字节）
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">            int ch = 0;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">            while ((ch = fr.read()) != -1) {<br>　　　　　　　　　　 //此处如果不转为字符串，会查找Unicode，而字符串也是使用的平台默认编码，所以需要转成字符串才不会乱码
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">                System.out.print((char) ch + "");
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">            }
    
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式二：批量读取字符到缓冲区</span>
               <span style="color: rgba(0, 0, 255, 1)">char</span>[] buffer =<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">char</span>[1024<span style="color: rgba(0, 0, 0, 1)">];
                </span><span style="color: rgba(0, 0, 255, 1)">int</span>  len = 0<span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len = fr.read(buffer)) != -1<span style="color: rgba(0, 0, 0, 1)">) {
                    System.out.print(</span><span style="color: rgba(0, 0, 255, 1)">new</span> String(buffer,0<span style="color: rgba(0, 0, 0, 1)">,len));
                }
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                e.printStackTrace();
            } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (fr != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                        fr.close();
                    }
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                    e.printStackTrace();
                }
            }</span></pre>
    </div>
    <p>下面代码演示了如何复制文本文件：</p>
    <div class="cnblogs_code">
    <pre> 　　　　<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">复制文本文件</span>
            String sourceFilePath = "D:\\Learning\\doc\\test.txt"<span style="color: rgba(0, 0, 0, 1)">;
            String destFilePath </span>= "D:\\Learning\\doc\\test1.txt"<span style="color: rgba(0, 0, 0, 1)">;
            FileReader fr </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            FileWriter fw</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                fr </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileReader(sourceFilePath);
                fw</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileWriter(destFilePath);
               </span><span style="color: rgba(0, 0, 255, 1)">char</span>[] buffer =<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">char</span>[1024<span style="color: rgba(0, 0, 0, 1)">];
                </span><span style="color: rgba(0, 0, 255, 1)">int</span>  len = 0<span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len = fr.read(buffer)) != -1<span style="color: rgba(0, 0, 0, 1)">) {
                    fw.write(buffer,</span>0<span style="color: rgba(0, 0, 0, 1)">,len);
                }
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                e.printStackTrace();
            } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (fr != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                        fr.close();
                    }
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (fw != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                        fw.close();
                    }
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                    e.printStackTrace();
                }
            }</span></pre>
    </div>
    <p>上面我们手动创建了缓冲区用来提高字符读写效率，java也提供了同样的功能，即BufferReader，BufferWriter。</p>
    <h3>BufferReader</h3>
    <p>从字符输入流中读取文本，缓冲各个字符，从而实现字符、数组和行的高效读取。可以指定缓冲区的大小，或者可使用默认的大小。大多数情况下，默认值就足够大了。</p>
    <p>构造函数如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">BufferedReader(Reader in)  创建一个使用默认大小输入缓冲区的缓冲字符输入流。
    BufferedReader(Reader in, </span><span style="color: rgba(0, 0, 255, 1)">int</span> sz)  创建一个使用指定大小输入缓冲区的缓冲字符输入流。</pre>
    </div>
    <p>reader方法如下：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">    read()  读取单个字符。
     </span><span style="color: rgba(0, 0, 255, 1)">int</span>    read(<span style="color: rgba(0, 0, 255, 1)">char</span>[] cbuf, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> len)  将字符读入数组的某一部分。
     String    readLine()  读取一个文本行。</span></pre>
    </div>
    <h3>BufferWriter</h3>
    <p>将文本写入字符输出流，缓冲各个字符，从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区的大小，或者接受默认的大小。在大多数情况下，默认值就足够大了。</p>
    <p>构造方法如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">BufferedWriter(Writer out)  创建一个使用默认大小输出缓冲区的缓冲字符输出流。
    BufferedWriter(Writer out, </span><span style="color: rgba(0, 0, 255, 1)">int</span> sz)  创建一个使用给定大小输出缓冲区的新缓冲字符输出流。</pre>
    </div>
    <p>writer方法如下：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">    newLine()  写入一个行分隔符。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">char</span>[] cbuf, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> len)  写入字符数组的某一部分。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> c)  写入单个字符。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(String s, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span> len)  写入字符串的某一部分。</pre>
    </div>
    <p>接下来看看如何使用：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 128, 0, 1)">　　　　 //</span><span style="color: rgba(0, 128, 0, 1)">复制文本文件</span>
            String sourceFilePath = "D:\\Learning\\doc\\git简单操作.txt"<span style="color: rgba(0, 0, 0, 1)">;
            String destFilePath </span>= "D:\\Learning\\doc\\test1.txt"<span style="color: rgba(0, 0, 0, 1)">;
            BufferedReader br </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            BufferedWriter bw </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                FileReader fr </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileReader(sourceFilePath);
                FileWriter fw </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileWriter(destFilePath);
                br </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedReader(fr);
                bw </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedWriter(fw);
                String line </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;//一行一行的读取和写入
                </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((line = br.readLine()) != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                    bw.write(line);
                    bw.newLine();
                }
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用缓冲对象一定要flush</span>
    <span style="color: rgba(0, 0, 0, 1)">            bw.flush();
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                e.printStackTrace();
            } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (br != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                        br.close();
                    }
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (bw != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
                        bw.close();
                    }
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                    e.printStackTrace();
                }
            }</span></pre>
    </div>
    <h3>LineNumberReader</h3>
    <p>跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber()，它们可分别用于设置和获取当前行号。</p>
    <p>默认情况下，行编号从 0 开始。该行号随数据读取在每个行结束符处递增，并且可以通过调用 setLineNumber(int) 更改行号。</p>
    <p>但要注意的是，setLineNumber(int) 不会实际更改流中的当前位置；它只更改将由 getLineNumber() 返回的值。</p>
    <p>下面看看简单的使用方式：</p>
    <div class="cnblogs_code">
    <pre>　　　　 String sourceFilePath = "D:\\Learning\\doc\\git简单操作.txt"<span style="color: rgba(0, 0, 0, 1)">;
            FileReader fr </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            LineNumberReader lnr </span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                fr </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileReader(sourceFilePath);
                lnr </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> LineNumberReader(fr);
                String line </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
                lnr.setLineNumber(</span>100<span style="color: rgba(0, 0, 0, 1)">);//设置起始行号为100
                </span><span style="color: rgba(0, 0, 255, 1)">while</span>((line=lnr.readLine())!=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){
                    System.out.println(lnr.getLineNumber()</span>+":"+<span style="color: rgba(0, 0, 0, 1)">line);
                }
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (FileNotFoundException e) {
                e.printStackTrace();
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                e.printStackTrace();
            }</span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span>(lnr!=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){
                    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                        lnr.close();
                    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (IOException e) {
                        e.printStackTrace();
                    }
                }
            }</span></pre>
    </div>
    <h2>转换流</h2>
    <h3>&nbsp;InputStreamReader</h3>
    <p>字节流通向字符流的桥梁：它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定，或者可以接受平台默认的字符集。</p>
    <p>为了达到最高效率，可要考虑在 BufferedReader 内包装 InputStreamReader。例如：</p>
    <div class="cnblogs_code">
    <pre>BufferedReader in= <span style="color: rgba(0, 0, 255, 1)">new</span> BufferedReader(<span style="color: rgba(0, 0, 255, 1)">new</span> InputStreamReader(System.in));</pre>
    </div>
    <p>构造方法如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">InputStreamReader(InputStream in)  创建一个使用默认字符集的 InputStreamReader。
    InputStreamReader(InputStream in, Charset cs)  创建使用给定字符集的 InputStreamReader。
    InputStreamReader(InputStream in, CharsetDecoder dec)  创建使用给定字符集解码器的 InputStreamReader。
    InputStreamReader(InputStream in, String charsetName)  创建使用指定字符集的 InputStreamReader。</span></pre>
    </div>
    <p>读取方法如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">    read() 读取单个字符。
    </span><span style="color: rgba(0, 0, 255, 1)">int</span>    read(<span style="color: rgba(0, 0, 255, 1)">char</span>[] cbuf, <span style="color: rgba(0, 0, 255, 1)">int</span> offset, <span style="color: rgba(0, 0, 255, 1)">int</span> length)  将字符读入数组中的某一部分。</pre>
    </div>
    <p>举个例子，比如获取键盘输入的内容，并打印在控制台上，要求不能用Scanner对象：</p>
    <div class="cnblogs_code">
    <pre>        <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需求：把键盘输入的内容打印在控制台</span>
            InputStreamReader isr = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> InputStreamReader(System.in);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式一：直接读取
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">        int ch = 0;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">        while ((ch=isr.read())!=-1){
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">            System.out.print((char) ch+"");
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">        }
    
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式二：读到缓冲区</span>
            <span style="color: rgba(0, 0, 255, 1)">int</span> len = 0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">char</span> [] buffer =<span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">char</span>[1024<span style="color: rgba(0, 0, 0, 1)">];
            </span><span style="color: rgba(0, 0, 255, 1)">while</span> ((len=isr.read(buffer))!=-1<span style="color: rgba(0, 0, 0, 1)">){
                System.out.print(</span><span style="color: rgba(0, 0, 255, 1)">new</span> String(buffer,0<span style="color: rgba(0, 0, 0, 1)">,len));
            }
    
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式三：使用缓冲流提供的便捷方法</span>
            BufferedReader br =<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedReader(isr) ;
            String line</span>=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">while</span>((line=br.readLine())!=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){
                System.out.print(line);
            }
        }</span></pre>
    </div>
    <h3>OutputStreamWriter</h3>
    <p> 是字符流通向字节流的桥梁：可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定，否则将接受平台默认的字符集。<br>为了获得最高效率，可考虑将 OutputStreamWriter 包装到 BufferedWriter 中，以避免频繁调用转换器。例如：</p>
    <div class="cnblogs_code">
    <pre>Writer out = <span style="color: rgba(0, 0, 255, 1)">new</span> BufferedWriter(<span style="color: rgba(0, 0, 255, 1)">new</span> OutputStreamWriter(System.out));</pre>
    </div>
    <p>构造方法如下：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">OutputStreamWriter(OutputStream out)  创建使用默认字符编码的 OutputStreamWriter。
    OutputStreamWriter(OutputStream out, Charset cs)  创建使用给定字符集的 OutputStreamWriter。
    OutputStreamWriter(OutputStream out, CharsetEncoder enc)  创建使用给定字符集编码器的 OutputStreamWriter。
    OutputStreamWriter(OutputStream out, String charsetName)  创建使用指定字符集的 OutputStreamWriter。</span></pre>
    </div>
    <p>写入方法如下：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">char</span>[] cbuf, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> len)  写入字符数组的某一部分。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> c)  写入单个字符。
     </span><span style="color: rgba(0, 0, 255, 1)">void</span>    write(String str, <span style="color: rgba(0, 0, 255, 1)">int</span> off, <span style="color: rgba(0, 0, 255, 1)">int</span> len)  写入字符串的某一部分。</pre>
    </div>
    <p>举个例子，比如把文本文件的内容打印在控制台上，要求不能用print方法：</p>
    <div class="cnblogs_code">
    <pre>        OutputStreamWriter osw=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> OutputStreamWriter(System.out);
            String line</span>="学习IO流"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式一：直接写入
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">        osw.write(line);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">        osw.close();
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方式二：使用缓冲流高效写入</span>
            BufferedWriter bw=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BufferedWriter(osw);
            bw.write(line);
            bw.close();</span></pre>
    </div>
    <p>再来个例子，将键盘录入的数据写入到一个文件中：</p>
    <div class="cnblogs_code">
    <pre> 　　　　String filePath="E:\\test.txt"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">需求：将键盘录入的数据写入到一个文件中。</span>
            BufferedReader bufr = <span style="color: rgba(0, 0, 255, 1)">new</span> BufferedReader(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> InputStreamReader(System.in));
            BufferedWriter bufw </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> BufferedWriter(<span style="color: rgba(0, 0, 255, 1)">new</span> OutputStreamWriter(<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> FileOutputStream(filePath)));
            String line </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">while</span>((line=bufr.readLine())!=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){
                </span><span style="color: rgba(0, 0, 255, 1)">if</span>(":wq"<span style="color: rgba(0, 0, 0, 1)">.equals(line))
                    </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                bufw.write(line.toUpperCase());
                bufw.newLine();
                bufw.flush();
            }</span></pre>
    </div>
    <p>上面的例子举得有点牵强，正在的用处在于上面这两个对象可以手动指定编码，比如读取文本文件，必须指定utf-8来编码。用FileReader是做不到的。</p>
    <div class="cnblogs_code">
    <pre>InputStreamReader isr = <span style="color: rgba(0, 0, 255, 1)">new</span> InputStreamReader(<span style="color: rgba(0, 0, 255, 1)">new</span> FileInputStream("E:\\test.txt"),"utf-8");</pre>
    </div>
    <p>&nbsp;</p>
    <p>参考文档：http://tool.oschina.net/apidocs/apidoc?api=jdk-zh</p>
    <p>参考代码：<a href="http://yun.itheima.com/course/7.html" target="_blank">毕老师35天</a></p>
    </div>
    
</body>
</html>